{-# OPTIONS -Wall #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  DirectoryMetrics.Compare
-- Copyright   :  (c) Stephen Peter Tetley 2012
-- License     :  BSD3
--
-- Maintainer  :  stephen.tetley@gmail.com
-- Stability   :  experimental
-- Portability :  to be determined
--
-- Comparisons of old and new directory structures.
--
-----------------------------------------------------------------------------


module DirectoryDiff.Compare
  (

    Moved(..)
  , ChangeSet(..)
  , diffDirectories  
  , diffFiles

  , sameWithIns
  ) where


import DirectoryDiff.BiParser
import DirectoryDiff.ResolvedSyntax

import Data.List


data Moved = Moved 
      { old_path :: FilePath
      , new_path :: FilePath
      }
  deriving (Eq,Ord,Show)


data ChangeSet = ChangeSet 
      { change_set_deleted :: [FilePath]
      , change_set_added   :: [FilePath]
      , change_set_moved   :: [Moved]
      }
  deriving (Eq,Ord,Show)


-- | Moved files are exlusively in new, but /resolve/ in old...
--
findMoves :: Atom -> [FilePath] -> [FilePath] -> ChangeSet
findMoves ins all_old all_new = 
    ChangeSet { change_set_deleted = olds
              , change_set_added   = news
              , change_set_moved   = moves
              }
  where
    init_old          = all_old \\ all_new
    init_new          = all_new \\ all_old
    moves             = foldr fn [] init_new
    moveLs            = map old_path moves
    moveRs            = map new_path moves
    olds              = filter (\a -> not $ elem a moveLs) init_old
    news              = filter (\a -> not $ elem a moveRs) init_new

    fn new ac         = case find (\o -> sameWithIns ins o new) init_old of
                          Nothing -> ac
                          Just old -> let a = Moved { old_path = old
                                                    , new_path = new }
                                      in (a:ac)




-- ChangeSet is the wrong structure, we want to show moves as 
-- old and new...

diffDirectories :: Atom -> Resolved -> Resolved -> ChangeSet
diffDirectories ins old new = findMoves ins (dirNames old) (dirNames new)

diffFiles :: Atom -> Resolved -> Resolved -> ChangeSet
diffFiles ins old new =  findMoves ins (fileNames old) (fileNames new)


sameWithIns :: Atom -> FilePath -> FilePath -> Bool
sameWithIns ins old new = 
    either (const False) id $  runParserEither test (atoms old) (atoms new)
  where
    test = prefix >> symbolL ins >> suffix >> return True